#include "stdafx.h"
#include "Direct3D10.h"
#include "..\Common\Model.h"
#include "..\Common\Scene.h"
#include "..\Window.h"
#include "..\GUI\GUI.h"
#include "..\..\Global\globaldef.h"

//#ifdef BUILD_D3D10

#pragma comment( lib, "dxgi.lib" )
#pragma comment( lib, "d3d10.lib" )
#pragma comment( lib, "d3dx10d.lib" )
#pragma comment( lib, "dxerr.lib" )
#pragma comment( lib, "dxguid.lib" )

ID3D10Device*				CD3D10::g_pd3dDevice = NULL;
CD3D10::tCurrentShader		CD3D10::g_pCurrentShader = {NULL, NULL};
ID3D10RenderTargetView*		CD3D10::g_pRenderTargetView = NULL;
ID3D10DepthStencilView*		CD3D10::g_pRenderDepthStencilView = NULL;
IDXGISwapChain*				CD3D10::g_pSwapChain = NULL;
ID3D10Query*				CD3D10::g_pSOQuery = NULL;
ID3DX10Sprite*				CD3D10::g_pSpriteBatch = NULL;
ID3DX10Sprite*				CD3D10::g_pFontBatch = NULL;
HANDLE						CD3D10::g_ShaderCompiling = NULL;

ID3D10BlendState*			CD3D10::g_pBlendState = NULL; 
//ID3D10DepthStencilState*	CD3D10::g_pDepthStencilState = NULL;
ID3D10RasterizerState*		CD3D10::g_pRasterizeState = NULL;

ID3DX10Font*				CD3D10::g_pd3dxFontBody = NULL;
ID3DX10Font*				CD3D10::g_pd3dxFontTitle = NULL;
ID3D10StateBlock*			CD3D10::g_pStateBlock = NULL;

#define D3D10_VERIFY(call) switch(call) {			\
	case S_FALSE: case S_OK:						\
	{												\
	break;											\
	}												\
case D3D10_ERROR_FILE_NOT_FOUND:					\
	{												\
	VTHROW_INTERNALERROR("File not found (D3D10)");	\
	break;											\
	}												\
	case D3DERR_INVALIDCALL:						\
	{												\
	VTHROW_INTERNALERROR("Invalid function call (D3D10)");	\
	break;											\
	}												\
	case D3DERR_WASSTILLDRAWING:					\
	{												\
	VTHROW_INTERNALERROR("Driver was busy (D3D10)");	\
	break;											\
	}												\
	case E_OUTOFMEMORY:								\
	{												\
	VTHROW_INTERNALERROR("Memory error (D3D10)");	\
	break;											\
	}												\
	default: case E_FAIL:							\
	{												\
	VTHROW_INTERNALERROR("Failed (D3D10)");			\
	break;											\
	}												\
}

bool GetTechniquePassCount(ID3D10Effect* pEffect, LPCSTR pTechnqiueName, UINT *pPassCount) {
	
	if(!pEffect || !pTechnqiueName || !pPassCount)
		return false;

	ID3D10EffectTechnique* pTechnqiue = pEffect->GetTechniqueByName(pTechnqiueName);
	if(!pTechnqiue)
		return false;

	D3D10_TECHNIQUE_DESC techniqueDesc;
	if(FAILED(pTechnqiue->GetDesc(&techniqueDesc)))
		return false;

	*pPassCount = techniqueDesc.Passes;
	return true;
}


inline bool CD3D10::GetTechniquePassDesc(ID3D10Effect* pEffect, LPCSTR pTechnqiueName, UINT passIdx, D3D10_PASS_DESC *pPassDesc) {
	
	if(!pEffect || !pTechnqiueName || !pPassDesc)
		return false;

	ID3D10EffectTechnique* pTechnqiue = pEffect->GetTechniqueByName(pTechnqiueName);
	if(!pTechnqiue)
		return false;

	ID3D10EffectPass* pPass = pTechnqiue->GetPassByIndex(passIdx);
	if(!pPass)
		return false;

	if(FAILED(pPass->GetDesc(pPassDesc)))
		return false;

	return true;
}

inline bool CD3D10::HasTechnique(ID3D10Effect* pEffect, LPCSTR pTechnqiueName) {
	
	if(!pEffect || !pTechnqiueName)
		return false;

	ID3D10EffectTechnique* pTechnqiue = pEffect->GetTechniqueByName(pTechnqiueName);
	if(!pTechnqiue)
		return false;

	D3D10_TECHNIQUE_DESC techDesc;
	if(FAILED(pTechnqiue->GetDesc(&techDesc)))
		return false;

	return true;
}

inline D3D10_RESOURCE_DIMENSION CD3D10::GetD3D10Type(Render::tResource* pResource) {

	if(!pResource)
		return D3D10_RESOURCE_DIMENSION_UNKNOWN;

	D3D10_RESOURCE_DIMENSION type;
	AS_D3D10_RESOURCE(pResource->pResource)->GetType(&type);
	return type;
}

/**
	Releases a resource. This function assumes that the resource being 
	released was created with a device instance that matches this device
	implementation.

	@author Dacre Denny
	@param pResource pointer to resource being released
	@return true if successful otherwise false
*/
bool CD3D10::ReleaseResource(Render::tResource** pResource) {

	if(!pResource)
		return false;

	Render::tResource* pR = *pResource;
	if(!pR)
		return false;

	FOREACH(Render::tResource*, i, Render::g_Resources) {

		Render::tResource* pIt = *i;
		if(pIt == pR) {

			Render::g_Resources.erase(i);
			if(pIt->pResource) {

				AS_D3D10_COM(pIt->pResource)->Release();
				pIt->pResource = NULL;
			}
			delete pIt;			
			*pResource = NULL;
			return true;
		}
	}

	return false;
}

/**
	Releases a shader. This function assumes that the shader being released was created 
	with a device instance that matches this device implementation.

	@author Dacre Denny
	@param pResource pointer to address of shader resource being released
	@return true if successful otherwise false
*/
bool CD3D10::ReleaseShader(Render::tShader** pInOut) {

	if(!pInOut)
		return false;

	Render::tShader* pShader = *pInOut;
	if(!pShader)
		return false;

	if(WaitForSingleObject(CD3D10::g_ShaderCompiling, INFINITE) == WAIT_ABANDONED)
		return false;

	FOREACH(Render::tShader*, i, Render::g_Shaders) {

		Render::tShader* pIt = *i;
		if(pIt == pShader) {

			if(Render::UpdateShaderRefCount(pShader, -1) == 0) {

				RELEASE_D3D10_RESOURCE(pIt->pEffect);
				ID3D10InputLayout** pInputDeclarations = (ID3D10InputLayout**)pIt->pInputDeclaration;
				if(pInputDeclarations) {

					RELEASE_D3D10_RESOURCE(pInputDeclarations[0]);
					RELEASE_D3D10_RESOURCE(pInputDeclarations[1]);
					delete [] pInputDeclarations;
					pIt->pInputDeclaration = NULL;
				}

				if(pShader == g_pDefaultShader)
					g_pDefaultShader = NULL;


				Render::g_Shaders.erase(i);
				delete pShader;
				*pInOut = NULL;
			}
			return true;
		}
	}

	return false;
}

/**
	Reloads all resource and shaders associated with this device instance. 
	This function assumes that the resources being reloaded were created with
	a device instance that matched this device implementation.

	@author Dacre Denny
	@return true if successful otherwise false
*/
bool CD3D10::ReloadResources() {
	
	Render::tShader* pShader		= NULL;
	ID3D10Effect* pEffect			= NULL;
	ID3D10Blob* pByteCode			= NULL;
	ID3D10InputLayout** pInputDeclarations = NULL;

	try {

		FOREACH(Render::tResource*, i, Render::g_Resources) {

			Render::tResource* pIt = *i;
			if(!pIt)
				VTHROW("Invalid resource encountered");

			switch(pIt->type) {
				case Render::VERTEX_BUFFER:
					{
#pragma message ("TO DO - vertex Buffer!")
					}break;

				case Render::TEXTURE:
					{
						ID3D10ShaderResourceView* pTextureView = NULL;
						if(!GetTextureView(pIt, &pTextureView))
							throw tException("Failed to aquire texture view");

						pTextureView->Release();
						pIt->pResource = NULL;
						D3D10_VERIFY(D3DX10CreateShaderResourceViewFromFile(CD3D10::g_pd3dDevice,
							pIt->filename.c_str(), NULL, NULL, (ID3D10ShaderResourceView**)&pIt->pResource, NULL))
					}break;
			}
		}

		if(WaitForSingleObject(CD3D10::g_ShaderCompiling, INFINITE) == WAIT_ABANDONED)
			throw tException("Failed to aquire shader lock");

		FOREACH(Render::tShader*, i, Render::g_Shaders) {

			tShader* pIt = *i;
	
#ifdef D3D_DIAG_DLL
			DWORD dwFlags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_DEBUG;
//#else
//			DWORD dwFlags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY;
#endif
			std::vector<D3D10_SHADER_MACRO> MacroDefinitions;
			std::vector<D3D10_INPUT_ELEMENT_DESC> elements;
			if(!CD3D10::GetShaderMacrosAndElements(pIt->VertexFormat, pIt->Attributes, &elements, &MacroDefinitions))
				throw tException("Failed to get shader elements and/or macros");

			std::string filePath = Render::SHADER_DIRECTORY + pIt->filename;
			if(FAILED(D3DX10CreateEffectFromFile(filePath.c_str(), (D3D10_SHADER_MACRO*)&MacroDefinitions[0], NULL, 
				"fx_4_0", dwFlags, 0, CD3D10::g_pd3dDevice, NULL, NULL, &pEffect, &pByteCode, NULL))) {

				if(!pByteCode) 
					throw tException("D3D10 error");
				
				char errorBuffer[1024] = {0};
				memcpy_s(errorBuffer, 1024, pByteCode->GetBufferPointer(), 1024 - 1);
				MessageBox(0, errorBuffer, "Error", 0);
				throw tException(errorBuffer);
			}

			if(pByteCode)
				pByteCode->Release();

			/*
			Create input declarations for each technique
			*/
			D3D10_PASS_DESC PassDesc;
			if(!GetTechniquePassDesc(pEffect, "Technique_Standard", 0,  &PassDesc))
				throw tException("Failed to parse shader technique");
			
			pInputDeclarations = new ID3D10InputLayout* [2];
			if(!pInputDeclarations)
				throw tException("Memory error");

			/*
			The last two elements, which will always be present, are specifically for the instanced technique
			*/
			if(FAILED(CD3D10::g_pd3dDevice->CreateInputLayout(&elements[0], elements.size() - 2,
				PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &pInputDeclarations[0])))
				throw tException();
			
			/*
			If the shader doesn't require instance streaming then it will have an instancing technique
			*/
			if(!(pIt->Attributes & INSTANCE_STREAMING)) {

				if(!GetTechniquePassDesc(pEffect, "Technique_Instanced", 0,  &PassDesc))
					throw tException("Failed to parse shader technique (instanced)");

				if(FAILED(CD3D10::g_pd3dDevice->CreateInputLayout(&elements[0], elements.size(),
				PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &pInputDeclarations[1])))
					throw tException();
			}
			else {

				pInputDeclarations[1] = NULL;
			}

			RELEASE_D3D10_RESOURCE(pIt->pEffect);
			pIt->pEffect = pEffect;

			if(pIt->pInputDeclaration) {

				ID3D10InputLayout** pCurrentDeclarations = (ID3D10InputLayout**)pIt->pInputDeclaration;
				if(pCurrentDeclarations) {

					RELEASE_D3D10_RESOURCE(pCurrentDeclarations[0]);
					RELEASE_D3D10_RESOURCE(pCurrentDeclarations[1]);
				}

				delete [] pCurrentDeclarations;
			}

			pIt->pInputDeclaration = pInputDeclarations;
			pIt->Print();
		}

		printf("------------------\nTotal Shaders:%i\n", Render::g_Shaders.size());

		return true;
	}
	catch(tException exception) {

		return false;
	}
}

/**
	Releases all resource and shaders associated with this device instance. 
	This function assumes that the resource being released were created with
	a device instance that matched this device implementation. The function
	also resets the device feilds, requiring Create(..) to be called if it is
	to be used again

	@author Dacre Denny
	@return true if successful otherwise false
*/
bool CD3D10::Release() {
	
	VTRY {

		if(Render::g_pVertexBuffer_Grid && !ReleaseResource(&Render::g_pVertexBuffer_Grid))
			VTHROW("Failed to release grid resource")

		FOREACH(Render::tResource*, i, Render::g_Resources) {

			Render::tResource* pIt = *i;
			if(pIt) {

				RELEASE_D3D10_RESOURCE(pIt->pResource)
				delete pIt;
			}
		}

		FOREACH(Render::tShader*, i, Render::g_Shaders) {

			Render::tShader* pIt = *i;
			if(pIt) {

				RELEASE_D3D10_RESOURCE(pIt->pEffect);
				delete pIt;
			}
		}

		Render::g_Resources.clear();
		Render::g_Shaders.clear();

		RELEASE_D3D10_RESOURCE(CD3D10::g_pSOQuery);
		RELEASE_D3D10_RESOURCE(CD3D10::g_pStateBlock);
		RELEASE_D3D10_RESOURCE(CD3D10::g_pSpriteBatch);
		RELEASE_D3D10_RESOURCE(CD3D10::g_pFontBatch);
		
		RELEASE_D3D10_RESOURCE(CD3D10::g_pd3dxFontBody);
		RELEASE_D3D10_RESOURCE(CD3D10::g_pd3dxFontTitle);
		RELEASE_D3D10_RESOURCE(CD3D10::g_pSwapChain);
		RELEASE_D3D10_RESOURCE(CD3D10::g_pRenderTargetView);
		RELEASE_D3D10_RESOURCE(CD3D10::g_pRenderDepthStencilView);
		
		if(CD3D10::g_ShaderCompiling) {

			WaitForSingleObject(CD3D10::g_ShaderCompiling, 5000);
			CloseHandle(CD3D10::g_ShaderCompiling);
			CD3D10::g_ShaderCompiling = NULL;
		}
		
		RELEASE_D3D10_RESOURCE(CD3D10::g_pd3dDevice);
		
		Render::g_pGridShader		= NULL;
		Render::g_pDefaultShader	= NULL;
		return true;
	
	}VCATCHONLY;

	return false;
}

/**
	Creates this device instance. If successful, the device will be in a state that is suitable 
	for rendering

	@author Dacre Denny
	@param hWnd handle to the host/parent window
	@return true if successful otherwise false
*/
bool CD3D10::Create(HWND hWnd) {

	HANDLE shaderCompiling			= NULL;
	RECT clientArea;
    ID3D10Texture2D* pDepthStencil	= NULL;
	ID3D10Texture2D* pBackBuffer	= NULL;
	ID3D10Device* pd3dDevice		= NULL;
	IDXGISwapChain* pSwapChain		= NULL;
	ID3D10RenderTargetView* pRenderTargetView = NULL;	
	ID3D10DepthStencilView* pRenderDepthStencilView = NULL;
	ID3DX10Font* pd3dxFontBody = NULL;
	ID3DX10Font* pd3dxFontTitle = NULL;
	ID3DX10Sprite* pSpriteBatch = NULL;
	ID3DX10Sprite* pFontBatch = NULL;
	
	ID3D10BlendState* pBlendState = NULL;
	/*ID3D10DepthStencilState* pDepthStencilState = NULL;*/

	ID3D10Query* pSOQuery = NULL;
    ID3D10StateBlock*	pStateBlock = NULL;

	VTRY {

		if(!hWnd)
			VTHROW("Precondition failed");
		
		CWindow::GetClientRectangle(&clientArea);
		UINT width = clientArea.right - clientArea.left;
		UINT height = clientArea.bottom - clientArea.top;
		if(height == 0)
			height = 1;

		shaderCompiling = CreateEvent(NULL, TRUE, TRUE, TEXT("Shader lock"));
		if(!shaderCompiling)
			VTHROW("Failed to create lock event");

		/*
			Create swap chain
		*/
		{
			DXGI_SWAP_CHAIN_DESC swapChainDesc;
			ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));

			swapChainDesc.BufferCount			= 1;
			swapChainDesc.BufferDesc.Width		= width;
			swapChainDesc.BufferDesc.Height		= height;
			swapChainDesc.BufferDesc.Format		= DXGI_FORMAT_R8G8B8A8_UNORM;
			swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
			swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
			swapChainDesc.BufferUsage			= DXGI_USAGE_RENDER_TARGET_OUTPUT;
			swapChainDesc.OutputWindow			= hWnd;
			swapChainDesc.SampleDesc.Count		= 1;
			swapChainDesc.SampleDesc.Quality	= 0;
			swapChainDesc.Windowed				= TRUE;

#ifdef D3D_DIAG_DLL
			if( FAILED( D3D10CreateDeviceAndSwapChain( NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL,
						D3D10_CREATE_DEVICE_DEBUG, D3D10_SDK_VERSION, &swapChainDesc, &pSwapChain, &pd3dDevice ) ) )
				VTHROW("Failed to create device and/or swap chain.");
			D3DX10DebugMute(TRUE);
#else
			if( FAILED( D3D10CreateDeviceAndSwapChain( NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL,
						0, D3D10_SDK_VERSION, &swapChainDesc, &pSwapChain, &pd3dDevice ) ) )
				VTHROW("Failed to create device and/or swap chain.");
#endif
			if(FAILED(pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D),(LPVOID*)&pBackBuffer)))
				VTHROW("Failed to get swap chain Buffer.");

			if(FAILED(pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView)))
				VTHROW("Failed to create render target view.");
		}

		/*
			Create depth Buffer
		*/
		{
			D3D10_TEXTURE2D_DESC depthDesc;
			D3D10_DEPTH_STENCIL_VIEW_DESC depthViewDesc;
			ZeroMemory( &depthDesc, sizeof(D3D10_TEXTURE2D_DESC));
			ZeroMemory( &depthViewDesc, sizeof(D3D10_DEPTH_STENCIL_VIEW_DESC));

			depthDesc.Width			= width;
			depthDesc.Height		= height;
			depthDesc.MipLevels		= 1;
			depthDesc.ArraySize		= 1;
			depthDesc.Format		= DXGI_FORMAT_D32_FLOAT;
			depthDesc.CPUAccessFlags = 0;
			depthDesc.SampleDesc.Count = 1;
			depthDesc.SampleDesc.Quality = 0;
			depthDesc.Usage			= D3D10_USAGE_DEFAULT;
			depthDesc.BindFlags		= D3D10_BIND_DEPTH_STENCIL;
			depthDesc.MiscFlags		= 0;

			depthViewDesc.Format = depthDesc.Format;
			depthViewDesc.Texture2D.MipSlice = 0;
			depthViewDesc.ViewDimension = (depthDesc.SampleDesc.Count > 1) ? 
				D3D10_DSV_DIMENSION_TEXTURE2DMS : 
				D3D10_DSV_DIMENSION_TEXTURE2D;

			if(FAILED(pd3dDevice->CreateTexture2D( &depthDesc, NULL, &pDepthStencil)))
				VTHROW("Failed to create depth target texture.");

			if(FAILED(pd3dDevice->CreateDepthStencilView( pDepthStencil, &depthViewDesc, &pRenderDepthStencilView)))
				VTHROW("Failed to create depth target view.");

		}
		
		/*
			Create viewport
		*/
		{
			D3D10_VIEWPORT matrixViewProjection;
			ZeroMemory( &matrixViewProjection, sizeof(matrixViewProjection));

			matrixViewProjection.Width		= clientArea.right - clientArea.left;
			matrixViewProjection.Height		= clientArea.bottom - clientArea.top;
			matrixViewProjection.MinDepth		= 0.0f;
			matrixViewProjection.MaxDepth		= 1.0f;
 			matrixViewProjection.TopLeftX		= clientArea.left;
			matrixViewProjection.TopLeftY		= clientArea.top;

			pd3dDevice->RSSetViewports( 1, &matrixViewProjection );
		}

		pBackBuffer->Release();
		pd3dDevice->OMSetRenderTargets( 1, &pRenderTargetView, pRenderDepthStencilView);

		if(!CD3D10::Release())
			VTHROW("Failed to release old renderer instance");

		if(!Render::Singleton()->CreateTexture("Shaders\\basedata.jpg", &Render::g_pProceduralBaseData, pd3dDevice))
			VTHROW("Failed to create procedural base data");

		Render::SetCameraProjection(D3DXToRadian( 70.0f ), float(width) / float(height), 0.1f, 100.0f);
		Render::SetCameraFrameNavigation(D3DXVECTOR3(0.0f,0.0f,0.0f), 0.0f, 0.0f);

		CD3D10::g_Camera.m_Forward = D3DXVECTOR3(0.0f,0.0f,1.0f);
		CD3D10::g_Camera.m_Right = D3DXVECTOR3(1.0f,0.0f,0.0f);
		CD3D10::g_Camera.m_Angles[0] = 0.0f;
		CD3D10::g_Camera.m_Angles[1] = 0.0f;

		/*
			Create Stream Out Query
		*/
		{
			D3D10_QUERY_DESC queryDesc;
			queryDesc.MiscFlags = 0;
			queryDesc.Query = D3D10_QUERY_SO_STATISTICS;
			if(FAILED(pd3dDevice->CreateQuery(&queryDesc, &pSOQuery)))
				VTHROW("Failed to create query.");
		}
		
		/*
			Create Font
		*/
		{
			D3DX10_FONT_DESC fontDesc;
			fontDesc.Height = 20;
			fontDesc.Width = 0;
			fontDesc.Weight = FW_NORMAL;
			fontDesc.MipLevels = 1;
			fontDesc.Italic = false;
			fontDesc.CharSet = ANSI_CHARSET;
			fontDesc.OutputPrecision = OUT_TT_PRECIS;
			fontDesc.Quality = CLIP_DEFAULT_PRECIS;
			fontDesc.PitchAndFamily = DEFAULT_PITCH;
			strcpy(fontDesc.FaceName, "Arial\n");
			if(FAILED(D3DX10CreateFontIndirect(pd3dDevice, &fontDesc, &pd3dxFontBody)))
				VTHROW("Failed to create font.");
			fontDesc.Height = 14;
			fontDesc.Weight = FW_NORMAL;
			strcpy(fontDesc.FaceName, "Arial\n");
			if(FAILED(D3DX10CreateFontIndirect(pd3dDevice, &fontDesc, &pd3dxFontTitle)))
				VTHROW("Failed to create font.");

		}
		/*
			Create Sprite
		*/
		{
			if(FAILED(D3DX10CreateSprite(pd3dDevice, 0, &pSpriteBatch)))
				VTHROW("Failed to create sprite.");
			if(FAILED(D3DX10CreateSprite(pd3dDevice, 0, &pFontBatch)))
				VTHROW("Failed to create sprite.");
		}

		/*
			Create State Block
		*/
		{
			D3D10_STATE_BLOCK_MASK mask;
			D3D10StateBlockMaskEnableAll(&mask);
			if(FAILED(D3D10CreateStateBlock(pd3dDevice, &mask, &pStateBlock)))
				VTHROW("Failed to state block.");
		}
		
		/*
			Create states
		*/
		//{
		//	D3D10_BLEND_DESC desc;
		//	ZeroMemory(&desc, sizeof(D3D10_BLEND_DESC));
		//	desc.AlphaToCoverageEnable = FALSE;
		//	desc.BlendEnable[0] = FALSE;
		//	desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
		//	if(FAILED(pd3dDevice->CreateBlendState(&desc, &pBlendState)))
		//		VTHROW("Failed to create state.");
		//}

		/*{
			D3D10_DEPTH_STENCIL_DESC desc;
			ZeroMemory(&desc, sizeof(D3D10_DEPTH_STENCIL_DESC));
			desc.DepthEnable = FALSE;
			desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ZERO;
			if(FAILED(pd3dDevice->CreateDepthStencilState(&desc, &pDepthStencilState)))
				VTHROW("Failed to create state.");

		}*/

		//{
		//	D3D10_RASTERIZER_DESC desc;
		//	ZeroMemory(&desc, sizeof(D3D10_RASTERIZER_DESC));
		//	desc.AntialiasedLineEnable = FALSE;
		//	desc.FillMode = D3D10_FILL_SOLID;
		//	desc.CullMode = D3D10_CULL_BACK;
		//	desc.FrontCounterClockwise = FALSE;
		//	desc.DepthBias = 0;
		//	desc.DepthBiasClamp = 0.0f;
		//	desc.DepthClipEnable = TRUE;
		//	desc.ScissorEnable = FALSE;
		//	desc.MultisampleEnable = FALSE;
		//	if(FAILED(pd3dDevice->CreateRasterizerState(&desc, &pRasterizeState)))
		//		VTHROW("Failed to create state.");

		//}
		
		CD3D10::g_pd3dDevice				= pd3dDevice;
		CD3D10::g_pSwapChain				= pSwapChain;
		CD3D10::g_pRenderTargetView			= pRenderTargetView;
		CD3D10::g_pRenderDepthStencilView	= pRenderDepthStencilView;
		CD3D10::g_pd3dxFontBody				= pd3dxFontBody;
		CD3D10::g_pd3dxFontTitle			= pd3dxFontTitle;
		CD3D10::g_pSpriteBatch				= pSpriteBatch;
		CD3D10::g_pFontBatch				= pFontBatch;
		CD3D10::g_ShaderCompiling			= shaderCompiling;

		CD3D10::g_pBlendState = pBlendState;
		/*CD3D10::g_pDepthStencilState = pDepthStencilState;*/
		CD3D10::g_pSOQuery					= pSOQuery;
		CD3D10::g_pStateBlock				= pStateBlock;

		return true;

	}
	VCATCHONLY;

	RELEASE_D3D10_RESOURCE(pd3dxFontBody);
	RELEASE_D3D10_RESOURCE(pd3dxFontTitle);
	RELEASE_D3D10_RESOURCE(pSpriteBatch);
	RELEASE_D3D10_RESOURCE(pFontBatch);
	

	RELEASE_D3D10_RESOURCE(pDepthStencil);
	RELEASE_D3D10_RESOURCE(pRenderTargetView);
	RELEASE_D3D10_RESOURCE(pRenderDepthStencilView);

	RELEASE_D3D10_RESOURCE(pBackBuffer);
	RELEASE_D3D10_RESOURCE(pSwapChain);

	RELEASE_D3D10_RESOURCE(pd3dDevice);
	CD3D10::Release();

	return false;
}

/**
	Aquires the pointer to a texture object if it exsists. The key of this aquisition is the filename
	of the desired texture object.

	@author Dacre Denny
	@param filename the identification of the textures to aquire
	@param pOut pointer to address to assign the found texture object if it is found
	@return true if successful otherwise false
*/
bool CD3D10::GetTexture(const std::string& filename, Render::tResource** pOut) {

	if(!pOut)
		return false;

	FOREACH(Render::tResource*, i, Render::g_Resources) {

		Render::tResource* pIt = *i;
		if(pIt->pResource) {

			if(pIt->type == Render::TEXTURE && 
				filename.compare(pIt->filename) == 0) {
				*pOut = pIt;
				return true;
			}
		}
	}

	*pOut = NULL;
	return false;
}

/**
	Creates a texture for this device based on the specified parameters. This function will search
	for an existing match of the data specified and return that if found. It will otherwise attempt
	to create a new texture.

	@author Dacre Denny
	@param filename the filepath to the textures data source
	@param pOut optional pointer to assign the texture object to
	@param pDevice optional pointer to device that owns this texture
	@return true if successful otherwise false
*/
bool CD3D10::CreateTexture(const std::string& filename, Render::tResource** pOut, LPVOID pDevice) {

	Render::tResource* pTexture = NULL;

	VTRY {

		if(filename.length() == 0)
			VTHROW_INTERNALERROR("Precondition failed");

		FOREACH(Render::tResource*, i, Render::g_Resources) {

			Render::tResource* pIt = *i;
			if(pIt->pResource) {

				if(pIt->type == Render::TEXTURE && 
					filename.compare(pIt->filename) == 0) {
					*pOut = pIt;
					return true;
				}
			}
		}
		
		pTexture = new Render::tResource();
		if(!pTexture)
			VTHROW_INTERNALERROR("Memory error");
		
		pTexture->pResource	= NULL;
		pTexture->filename	= filename;
		pTexture->type		= Render::TEXTURE;
		pTexture->pResource	= NULL;
		
		D3D10_VERIFY(D3DX10CreateShaderResourceViewFromFile(pDevice ? (ID3D10Device*)pDevice : CD3D10::g_pd3dDevice, 
			filename.c_str(), NULL, NULL, (ID3D10ShaderResourceView**)&pTexture->pResource, NULL));

		Render::g_Resources.push_back(pTexture);
		if(pOut)
			*pOut = pTexture;

		return true;

	}VCATCHONLY;

	if(pTexture) {

		RELEASE_D3D10_RESOURCE(pTexture->pResource);
		delete pTexture;
	}

	if(pOut) {
		if(*pOut)
			*pOut = NULL;
	}

	return false;
}

D3D10_SHADER_MACRO GetMacro(char *pName, char* pDefinition) {

	D3D10_SHADER_MACRO macro;

	uint length;
	char *pStr;

	length = pName ? max(1, strlen(pName)) : 1;
	pStr = new char [length + 1];
	if(pName) 
		memcpy(pStr, pName, length);
	else
		pStr[0] = '\0';
	pStr[ length ] = '\0';
	macro.Name = pStr;
	
	length = pDefinition ? max(1, strlen(pDefinition)) : 1;
	pStr = new char [length + 1];
	if(pDefinition) 
		memcpy(pStr, pDefinition, length);
	else
		pStr[0] = '\0';
	pStr[ length ] = '\0';
	macro.Definition = pStr;
	
	return macro;
}

bool CD3D10::ReleaseShaderMacros(std::vector<D3D10_SHADER_MACRO> *pMacros) {

	if(pMacros) {

		for(std::vector<D3D10_SHADER_MACRO>::iterator i = pMacros->begin(); i != pMacros->end(); i++) {

			if(i->Definition)
				delete [] i->Definition;
			if(i->Name)
				delete [] i->Name;
		}

		pMacros->clear();
		return true;
	}

	return false;
}

bool CD3D10::GetShaderMacrosAndElements(const uint VertexFormat, const uint Attributes, std::vector<D3D10_INPUT_ELEMENT_DESC> *pOutElements, std::vector<D3D10_SHADER_MACRO> *pOutMacros) {

	if(!pOutElements || !pOutMacros)
		return false;

	bool requestDeformation = (VertexFormat & VERTEX_DEFORMATION);
	std::vector<D3D10_INPUT_ELEMENT_DESC> elements;
	std::string soFormat = std::string();
	char bufferName[128];
	char bufferDefn[128];


	/*
	These local macros construct of format string which is passed to the shader as a shader macro. The value
	tells the shader the format inwhich it should feed data out from pass 'n' in the deformation process into
	pass 'n + 1'
	*/
	#define SO_NUMERICAL_SEMANTIC(semantic, index, components) { \
		char so_num_tmp[32] = {0};	\
		sprintf(so_num_tmp, "%s%i.%s; ", semantic, index, components == 4 ? "xyzw" : components == 3 ? "xyz" : components == 2 ? "xy" : "x"); \
		soFormat.append(so_num_tmp); \
	}
	#define SO_SEMANTIC(semantic, components) { \
		char so_tmp[32] = {0};	\
		sprintf(so_tmp, "%s.%s; ", semantic, components == 4 ? "xyzw" : components == 3 ? "xyz" : components == 2 ? "xy" : "x"); \
		soFormat.append(so_tmp); \
	}
		
	/*
	Construct input elements for the shader based on vertex format. uvIndex starts at 1 because 0 is used by tangent
	*/
	UINT components;
	for(uint i = 0, offset = 0, uvIndex = 1; i < VERTEX_ELEMENT_COUNT; i++) {
	
		uint vertexField = 1 << i;	
		/*
		If the input format required this particular element. Always process instance elements for end of element list
		*/
		if(VertexFormat & vertexField || (vertexField & (VERTEX_INSTANCE_POSITION | VERTEX_INSTANCE_ROTATION))) {
			
			memset(bufferName, 0, 128);
			sprintf_s(bufferName, 128, "%s", (char*)vertex_elements[i]);
			/*
			D3D10_SHADER_MACRO macro = {wuffer, "\0"};*/
			//SetMacroField(&macro.Name, Buffer);
			//macro.Definition = "\0";
			pOutMacros->push_back(GetMacro(bufferName, ""));

			D3D10_INPUT_ELEMENT_DESC element;
			memset(&element, 0, sizeof(D3D10_INPUT_ELEMENT_DESC));
			element.AlignedByteOffset	= offset;
			element.InputSlotClass		= D3D10_INPUT_PER_VERTEX_DATA;

			switch(vertexField) {

				case VERTEX_POSITION: {

					components = 3;
					element.SemanticName = "SV_Position";
					element.Format = DXGI_FORMAT_R32G32B32_FLOAT;

					if(requestDeformation) 
						SO_SEMANTIC("SV_Position", (components));
					break;
				}

				case VERTEX_NORMAL: {

					components = 3;
					element.SemanticName = "NORMAL";
					element.Format = DXGI_FORMAT_R32G32B32_FLOAT;

					if(requestDeformation) 
						SO_SEMANTIC("NORMAL", components);
					break;
				}

				case VERTEX_TANGENT: {

					components = 3;
					element.SemanticName = "TEXCOORD";
					element.SemanticIndex = 0;
					element.Format = DXGI_FORMAT_R32G32B32_FLOAT;

					if(requestDeformation) 
						SO_NUMERICAL_SEMANTIC("TEXCOORD", 0, components);
					break;
				}

				case VERTEX_UV0: case VERTEX_UV1: case VERTEX_UV2: {

					components = 2;
					element.SemanticName = "TEXCOORD";
					element.SemanticIndex = uvIndex;
					element.Format = DXGI_FORMAT_R32G32_FLOAT;
					if(requestDeformation) 
						SO_NUMERICAL_SEMANTIC("TEXCOORD", uvIndex, components);
					
					uvIndex++;
					break;
				}
				case VERTEX_COLOR:
				{
					components = 4;
					element.SemanticName = "COLOR";
					element.SemanticIndex = 0;
					element.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;

					if(requestDeformation) 
						SO_NUMERICAL_SEMANTIC("COLOR", 0, components);
					break;
				}

				case VERTEX_DEFORMATION: {

					components = 2;
					element.SemanticName = "TEXCOORD";
					element.SemanticIndex = 5;
					element.Format = DXGI_FORMAT_R32G32_FLOAT;

					if(requestDeformation) 
						SO_NUMERICAL_SEMANTIC("TEXCOORD", 5, components);
					
					break;
				}
				
				case VERTEX_INSTANCE_POSITION:	{

					components = 4;
					element.AlignedByteOffset = 0;
					element.SemanticName = "INST_POSITION";
					element.SemanticIndex = 0;
					element.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
					element.InputSlotClass = D3D10_INPUT_PER_INSTANCE_DATA;
					element.InstanceDataStepRate = 1;
					element.InputSlot = 1;
					break;
				}

				case VERTEX_INSTANCE_ROTATION:	{ 

					components = 4;
					element.AlignedByteOffset = components * sizeof(float);
					element.SemanticName = "INST_SCALE_ROTATE";
					element.SemanticIndex = 0;
					element.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
					element.InputSlotClass = D3D10_INPUT_PER_INSTANCE_DATA;
					element.InstanceDataStepRate = 1;
					element.InputSlot = 1;
					break;
				}
				
				default: {

					continue;
					break;
				}
			}

			pOutElements->push_back(element);
			offset += (components * sizeof(float));
		}
	}		
	
	/*
	Declare SO format for multipass deformation if required
	*/
	if(requestDeformation) {
	
		soFormat.insert(soFormat.begin(), '\"');
		soFormat.insert(soFormat.end(), '\"');
		pOutMacros->push_back(GetMacro("SO_FORMAT", (char*)soFormat.c_str()));
	}

	/*
	Declare instance streaming in shader if required
	*/
	if(Attributes & INSTANCE_STREAMING)
		pOutMacros->push_back(GetMacro("INSTANCE_STREAMING", ""));

	/*
	Declare the samplers required for each channel
	*/
	for(uint c = 0; c < CHANNEL_COUNT; c++) {

		/*
		Check to see what channels are active for the input attributes
		0x7F = 01111111
		*/
		bool isChannelRequired = ((0x7F << (CHANNEL_BITWIDTH * c)) & Attributes);
		if(isChannelRequired) {
	
			D3D10_SHADER_MACRO macro;

			const char* channel = channels[c];
			memset(bufferName, 0, 128);
			sprintf_s(bufferName, 128, "%s", channel);

			memset(bufferDefn, 0, 128);
			sprintf_s(bufferDefn, 128, "%i", (c));
			
			pOutMacros->push_back( GetMacro(bufferName, bufferDefn) );
			
			/*
			Check to see what samplers are required for this active channel
			*/
			for(uint s = 0; s < SAMPLE_COUNT; s++) {
				
				bool isSamplerRequired = Attributes & ((1 << s) << (c * CHANNEL_BITWIDTH));
				if(isSamplerRequired)
				{
					const char* sampler = samplers[s];
					memset(bufferName, 0, 128);
					sprintf_s(bufferName, 128, "%s_%s", sampler, channel);
					pOutMacros->push_back(GetMacro(bufferName, ""));
				}
			}
		}

		/*
		if(Attributes & (DIMENSIONS_3D << (CHANNEL_BITWIDTH * c))) {
		
			sprintf_s(bufferName, 128, "DIMENSIONS_3D_%s", channel);
			pOut->push_back(tStringPair(std::string(bufferName), "1"));
		}
		*/
	}

	D3D10_SHADER_MACRO terminator = {NULL, NULL};
	pOutMacros->push_back(terminator);

	return true;
}

struct tShaderParams {

	char filename[32];
	Render::tShader* pShader;
	uint VertexFormat;
	uint Attributes;
	ID3D10Device* lpDevice;
	DWORD dwFlags;
	HANDLE m_Thread;

};

DWORD WINAPI CD3D10::ShaderCompileWorker( LPVOID lpParam) {

	GUI::PrintMessage("Thread started [HLSL compiler]...");

	tShaderParams* pThreadParam = (tShaderParams*)lpParam;
	ID3D10InputLayout** pInputDeclarations = NULL;
	ID3D10Blob* pByteCode = NULL;
	ID3D10Effect* pEffect = NULL;
	std::vector<D3D10_SHADER_MACRO> Macros;
	std::vector<D3D10_INPUT_ELEMENT_DESC> VertexElements;
	
	try {

		if(!pThreadParam)
			throw tException();

		Render::tShader* pShader = pThreadParam->pShader;
	
		/*
		Construct macro and input element lists that comply with the required input formats and attributes
		*/
		GUI::PrintMessage("[HLSL compiler] Building macro list");
		if(!CD3D10::GetShaderMacrosAndElements(pThreadParam->VertexFormat, pThreadParam->Attributes, &VertexElements, &Macros))
			throw tException("Failed to get shader VertexElements and/or macros");
	
		if(Macros.size() == 0)
			throw tException("Macro list empty");

		/*
		Load and compile the shader
		*/
		std::string filePath;
		filePath.append(Render::SHADER_DIRECTORY);
		filePath.append(pThreadParam->filename);
		GUI::PrintMessage("[HLSL compiler] Compiling '%s'", pThreadParam->filename);
		if(FAILED(D3DX10CreateEffectFromFile(filePath.c_str(), (D3D10_SHADER_MACRO*)&Macros[0], NULL, 
			"fx_4_0", pThreadParam->dwFlags, 0, pThreadParam->lpDevice, NULL, NULL, &pEffect, &pByteCode, NULL))) {

			if(!pByteCode) 
				throw tException("D3D10 shader compile error");
			else
				throw tException((const char*)pByteCode->GetBufferPointer());
		}

		CD3D10::ReleaseShaderMacros(&Macros);

		/*
		Create input declarations for each technique
		*/
		GUI::PrintMessage("[HLSL compiler] Parsing input layout, techniques, passes...");
		D3D10_PASS_DESC PassDesc;
		if(!CD3D10::GetTechniquePassDesc(pEffect, "Technique_Standard", 0,  &PassDesc))
			throw tException("Failed to parse shader technique");
		
		pInputDeclarations = new ID3D10InputLayout* [2];
		if(!pInputDeclarations)
			throw tException("Memory error");

		/*
		The last two VertexElements, which will always be present, are specifically for the instanced technique
		*/
		if(FAILED(pThreadParam->lpDevice->CreateInputLayout(&VertexElements[0], VertexElements.size() - 2,
			PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &pInputDeclarations[0])))
			throw tException();
		
		/*
		If the shader doesn't require instance streaming then it will have an instancing technique
		*/
		bool requestSOInstancing = (pThreadParam->Attributes & INSTANCE_STREAMING);
		if(!requestSOInstancing) {

			if(!CD3D10::GetTechniquePassDesc(pEffect, "Technique_Instanced", 0,  &PassDesc))
				throw tException("Failed to parse shader technique (instanced)");

			if(FAILED(pThreadParam->lpDevice->CreateInputLayout(&VertexElements[0], VertexElements.size(),
			PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &pInputDeclarations[1])))
				throw tException();
		}
		else {

			pInputDeclarations[1] = NULL;
		}

		pShader->pEffect		= pEffect;
		pShader->pInputDeclaration = pInputDeclarations;
		
		delete pThreadParam;
		GUI::PrintMessage("[HLSL compiler] Done");

	}catch(tException exception) {

		CD3D10::ReleaseShaderMacros(&Macros);
		
		RELEASE_D3D10_RESOURCE(pByteCode);
		RELEASE_D3D10_RESOURCE(pEffect);

		CD3D10::ReleaseShaderMacros(&Macros);
		FOREACH(D3D10_INPUT_ELEMENT_DESC, i, VertexElements) {
			if((*i).SemanticName)
				delete [] (*i).SemanticName;
		}

		if(pInputDeclarations) {

			RELEASE_D3D10_RESOURCE(pInputDeclarations[0]);
			RELEASE_D3D10_RESOURCE(pInputDeclarations[1]);

			delete [] pInputDeclarations;
		}		
		
		GUI::PrintError("[HLSL compiler] %s", exception.Message.c_str());
	
	}

	SetEvent(CD3D10::g_ShaderCompiling);
	return 0;
}

/**
	Creates a shader for this device based on the specified parameters. This function will search for 
	an existing match of the data specified and return that if found. It will otherwise attempt to creat 
	a new shader.

	@author Dacre Denny
	@param filename file path of shader source
	@param VertexFormat a bit field specifiying the composition of the input data stream
	@param Attributes feature set describing sampler combinations for this shader
	@param pInOut optional pointer for external storage. This device still owns the shader is a valid pointer is provided. If the pointer provided is valid it will be replace
	@param forceReload option flag to indicate if the renderer should reparse the shader file
	@param pDevice optional pointer to device that will own this shader
	@return true if successful otherwise false
*/
bool CD3D10::GetShader(const std::string& filename, const uint VertexFormat, const uint Attributes, Render::tShader** pOut, bool forceReload, LPVOID pDevice) {

	Render::tShader* pShader		= NULL;
	ID3D10Device* pTargetDevice		= pDevice ? (ID3D10Device*)pDevice : CD3D10::g_pd3dDevice;
	ID3D10Effect* pEffect			= NULL;
	ID3D10Blob* pByteCode			= NULL;
	ID3D10InputLayout** pInputDeclarations = NULL;
	std::vector<D3D10_SHADER_MACRO> MacroDefinitions;
	
#ifdef D3D_DIAG_DLL
	DWORD dwFlags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY | D3D10_SHADER_DEBUG;
#else
	DWORD dwFlags = D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY;
#endif

	try {
		
		if(filename.length() == 0 || VertexFormat == 0 || !pOut)
			throw tException("Precondition(s) failed");

		/*bool requestDeformation = (VertexFormat & VERTEX_DEFORMATION);*/
		bool requestPosition = (VertexFormat & VERTEX_POSITION);
		bool requestDeformation = (VertexFormat & VERTEX_DEFORMATION);
		bool requestNormal = (VertexFormat & VERTEX_NORMAL);
		bool requestUV = (VertexFormat & (VERTEX_UV0 | VERTEX_UV1 | VERTEX_UV2));
		bool requestSOInstancing = (Attributes & INSTANCE_STREAMING);

		if(requestSOInstancing && !(requestUV && requestPosition))
			throw tException("Cannot create shader. Stream out for instances requires vertex format with UV coordinates and position.");
		
		if(requestDeformation && (!requestUV || !requestNormal))
			throw tException("Cannot create shader. Deformation requires per vertex UV and normal data.");
		
		/*
		Attempt to locate a precached match
		*/
		bool wasPrecached = false;
		if(Render::GetPrecached(filename, VertexFormat, Attributes, pOut)) {

			/*
			If not required to reload this shader return found instance
			*/
			if(!forceReload)
				return true;

			wasPrecached = true;
		}

		
		switch(WaitForSingleObject(CD3D10::g_ShaderCompiling, 15000)) {
			case WAIT_TIMEOUT:
			case WAIT_FAILED:
			case WAIT_ABANDONED:
				throw tException("Failed to aquire shader lock");
			case WAIT_OBJECT_0:
				break;
		}
		ResetEvent(CD3D10::g_ShaderCompiling);

		/*
		If the shader was pre cached but the client is requesting reload then resuse this pointer
		*/
		pShader = wasPrecached ? *pOut : new tShader();
		
		/*
		Creating compiler worker thread
		*/
		tShaderParams* pParms = new tShaderParams();
		pParms->dwFlags = dwFlags;
		memcpy(&pParms->filename, &filename[0], sizeof(char) * 32);
		pParms->lpDevice = pTargetDevice;
		pParms->VertexFormat = VertexFormat;
		pParms->Attributes = Attributes;
		pParms->pShader = pShader;

		HANDLE hThread = CreateThread(NULL,0, CD3D10::ShaderCompileWorker, pParms, CREATE_SUSPENDED, NULL);
		if(hThread == NULL)
			throw tException("Failed to spawn shader compilation thread");
		
		/*
		Assign the filename immediatly because it is a key for the object which may be used during the worker threads life time
		If this isn't avalible immediatly, the object being created could be recreated while this worker thread is still compiling 
		the same shader
		*/
		pShader->filename		= filename;
		pShader->Attributes		= Attributes;
		pShader->VertexFormat	= VertexFormat;
		pShader->pEffect		= NULL;
		pParms->m_Thread		= hThread;
		pShader->pInputDeclaration = NULL;
		Render::UpdateShaderRefCount(pShader, 1);
		Render::g_Shaders.push_back(pShader);
		
		ResumeThread(hThread);
		*pOut = pShader;

		RELEASE_D3D10_RESOURCE(pByteCode);
		return true;

	}catch(tException exception) {
	
		ReleaseShaderMacros(&MacroDefinitions);

		RELEASE_D3D10_RESOURCE(pEffect);
		RELEASE_D3D10_RESOURCE(pByteCode);

		if(pShader)
			delete pShader;
	
		return false;
	}
}

/**
	Utilizes the streaming capabilities of Direct3D 10 to generate instance transformations across a parent meshes geometery. These transformations
	are then used to instance child geometry across the parent geometry.

	@author Dacre Denny
	@param filename file path of shader source
	@param pCookie optional pointer to texture for cookie profile
	@param VertexFormat a bit field specifiying the composition of the input data stream
	@param Attributes feature set describing sampler combinations for this shader
	@param pInOut optional pointer for external storage. This device still owns the shader is a valid pointer is provided. If the pointer provided is valid it will be replace
	@param pDevice optional pointer to device that will own this shader
	@return true if successful otherwise false
*/
bool CD3D10::StreamOutToBuffer(tPart* pParentMesh,Render::tResource* pCookie, int uvChannel, D3DXMATRIX* pWorld, tInstanceChild* pChild,uint* pPrimitvesWritten) {

	try {

		/*
		Check basic preconditions
		*/
		if(!pParentMesh || !pChild)
 			throw tException("Preconditions failed.");
 
		Render::tResource* pInstanceBuffer = pChild->m_pBuffer;
		if(!pInstanceBuffer)
			throw tException();
		if(pInstanceBuffer->type != Render::VERTEX_BUFFER)
			throw tException();

		Render::tShader* pShader = pParentMesh->m_pShader;
		if(!pShader)
			throw tException("Invalid shader.");
		
		/*
		Create a version of the mesh's shader that is compiled to support instance out streaming. This shader dosn't need
		any sampler attributes etc, so just request the result to have instance streaming attribute. Doing this ensures consistant
		behaviour for instance placement across geometry that may be distrubed in some way by the geometrys shader
		*/
		Render::tShader* pSOInstance = NULL;
		if(!GetShader(pShader->filename, pShader->VertexFormat, INSTANCE_STREAMING, &pSOInstance, false))
			throw tException("Failed to aquire instancing shader variant.");

		/*
		If the client is requesting the number of instances written, a stream out query must monitor the rendering process
		*/
		if(pPrimitvesWritten)
			CD3D10::g_pSOQuery->Begin();


		/*
		Begin 'rendering' the parent geometry, which will cause instance transforms to be streamed back to the CPU
		*/
		uint shaderPasses = 0;
		ID3D10Buffer* pBuffers[1];
		uint offset;
		if(Render::Singleton()->BeginShader(pSOInstance, false, &shaderPasses)) {
			
			if(pWorld)
				Render::Singleton()->SetShaderMatrix( "World", pWorld);
			if(pCookie)
				Render::Singleton()->SetShaderTexture(0, pCookie);
			
			Render::Singleton()->SetShaderFloat("uv_channel", uvChannel);
			Render::Singleton()->SetShaderFloat("MaskControl", pCookie ? 1.0f : 0.0f);

			uint samplerTypes[3];
			Materials::GetType(pChild->m_hChannels[0], &samplerTypes[0]);
			Materials::GetType(pChild->m_hChannels[1], &samplerTypes[1]);
			Materials::GetType(pChild->m_hChannels[2], &samplerTypes[2]);
			
			Materials::ApplyToShader(pSOInstance, "liveview_position", pChild->m_hChannels[0]);
			Materials::ApplyToShader(pSOInstance, "liveview_rotation", pChild->m_hChannels[1]);
			Materials::ApplyToShader(pSOInstance, "liveview_scale", pChild->m_hChannels[2]);

			Render::Singleton()->SetShaderInt("position_type", samplerTypes[0]);
			Render::Singleton()->SetShaderInt("rotation_type", samplerTypes[1]);
			Render::Singleton()->SetShaderInt("scale_type", samplerTypes[2]);

			/*
			Initalize the stream out target so that the streamed data can be subsequently used
			*/
			offset = 0;
			pBuffers[0] = (ID3D10Buffer*)pInstanceBuffer->pResource;
			CD3D10::g_pd3dDevice->SOSetTargets(1, pBuffers, &offset);
						
			for(uint j = 0; j < shaderPasses; j++) {

				if(!Render::Singleton()->BeginShaderPass(j))
					continue;

				/*
				Bind the geometry of the parent mesh and render it depending on it's data composition
				*/
				Render::tResource* pVertexBuffer = pParentMesh->m_pVertexBuffer;
				Render::tResource* pIndexBuffer = pParentMesh->m_pIndexBuffer;
				uint vertexFormatSize = GetVertexFormatSize(pSOInstance->VertexFormat);
				
				if(!Render::Singleton()->BindVertexBuffer(&pVertexBuffer, &vertexFormatSize, 1))
					continue;

				if(pIndexBuffer) {
				
					if(!Render::Singleton()->BindIndexBuffer(pIndexBuffer, sizeof(uint)))
						continue;

					Render::Singleton()->DrawIndexedTriangleList(pParentMesh->m_TriangleCount, NULL, NULL);
				}
				else {

					Render::Singleton()->DrawTriangleList(pParentMesh->m_TriangleCount, NULL);
				}
				
				Render::Singleton()->EndShaderPass();
			}
		
			Render::Singleton()->EndShader();
		}

		/*
		If the client requested to know the number of instances written, assume a stream out query was run. End the query, and collect the query
		results. Return these to the client.
		*/
		if(pPrimitvesWritten) {

			CD3D10::g_pSOQuery->End();

			D3D10_QUERY_DATA_SO_STATISTICS SOStats;
			uint maxWait = 1000;
			for(uint maxWait = 1000; S_OK != CD3D10::g_pSOQuery->GetData(&SOStats, sizeof(D3D10_QUERY_DATA_SO_STATISTICS), 0); maxWait--) {

				if(maxWait == 0)
					throw tException("Stream out query time-out");
				Sleep(5);
			}

			*pPrimitvesWritten = SOStats.NumPrimitivesWritten;
		}

		/*
		Good practice with D3D10
		*/
		pBuffers[0] = NULL;
		offset = 0;
		CD3D10::g_pd3dDevice->SOSetTargets(1, pBuffers, &offset);

		/*
		This allows an instance of the stream out shader for instancing to reside in memory which will prevent the need for it
		to be recreated on every frame. It also prevents the shaders reference count from incrementing continuosly
		*/
		uint refCount = Render::UpdateShaderRefCount(pSOInstance, 0);
		if(refCount > 1)
			Render::UpdateShaderRefCount(pSOInstance, -1);

		return true;

	}catch(tException exception) {

		return false;
	}
}

/**
	Renders a batch of triangles that has been bound to the device via a vertex Buffer.
	If a valid point is passed to the second parameter the function will draw multiple
	instances of the triangle mesh according to the dereferenced value of the respective 
	pointer

	@author Dacre Denny
	@param elementCount the number of triangle to be drawn
	@param pInstanceCount the number of instances to draw (when dereferenced)
	@return true if successful otherwise false
*/
bool CD3D10::DrawTriangleList(UINT elementCount, UINT* pInstanceCount) {

	if(elementCount == 0)
		return false;
	
	CD3D10::g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ);
	if(pInstanceCount) {

		CD3D10::g_pd3dDevice->DrawInstanced(elementCount * 3, *pInstanceCount ,0, 0);
	}
	else {

		CD3D10::g_pd3dDevice->Draw(elementCount * 3*2, 0);
	}

	return true;
}

/**
	Renders a batch of triangles that has been bound to the device via a vertex Buffer.
	The rendering is dictated by the index Buffer that has already been bound to the device.
	If a valid point is passed to the second parameter the function will draw multiple
	instances of the triangle mesh according to the dereferenced value of the respective 
	pointer

	@author Dacre Denny
	@param indicieCount the number of indicies in the currently bound index Buffer
	@param pInstanceCount the number of instances to draw (when dereferenced)
	@param pDeformationPass the current deformation pass if the geometry being rendered is subjected to deformation. If NULL, this is assumed not to be the case
	@return true if successful otherwise false
*/
bool CD3D10::DrawIndexedTriangleList(UINT triangelCount, UINT* pInstanceCount, UINT *pDeformationPass) {

	if(triangelCount == 0)
		return false;

	/*
	Assume no geometry shader or no multipass geometry emmsion, use regular draw methods
	*/
	bool drawAuto = false;
	if(pDeformationPass)
		drawAuto = (*pDeformationPass > 0);

	if(drawAuto) {
		
		
		CD3D10::g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
		CD3D10::g_pd3dDevice->DrawAuto();
	}
	else {

		CD3D10::g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ);
		if(pInstanceCount) {

			/*
			//For debugging
			for(uint i = 0; i < *pInstanceCount; i++)
				CD3D10::g_pd3dDevice->DrawIndexedInstanced(triangelCount * 2 * 3, 1,0,0, i);*/
			
			CD3D10::g_pd3dDevice->DrawIndexedInstanced(triangelCount * 2 * 3, *pInstanceCount, 0, 0, 0);
		}
		else {

			CD3D10::g_pd3dDevice->DrawIndexed(triangelCount * 3 * 2, 0, 0);
		}
	}

	//ID3D10EffectPass* pCurrentPass = CD3D10::g_pCurrentShader.m_pTechnique->GetPassByIndex(CD3D10::g_pCurrentShader.m_OnPass);
	//D3D10_TECHNIQUE_DESC td;
	//CD3D10::g_pCurrentShader.m_pTechnique->GetDesc(&td);
	//
	//D3D10_PASS_SHADER_DESC geometryShaderPassDesc;

	//ID3D10Buffer* pCurrentSOBuffer = NULL;
	//UINT curretSOOffset = 0;
	//CD3D10::g_pd3dDevice->SOGetTargets(1, &pCurrentSOBuffer, &curretSOOffset);

	//if(CD3D10::g_pCurrentShader.m_OnPass > 0 && pCurrentSOBuffer) {

	//	if(td.Passes - 1 == CD3D10::g_pCurrentShader.m_OnPass) {
	//
	//		pCurrentSOBuffer = NULL;
	//		curretSOOffset = 0;
	//		CD3D10::g_pd3dDevice->SOSetTargets(1, &pCurrentSOBuffer, &curretSOOffset);
	//	}

	//	CD3D10::g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	//	CD3D10::g_pd3dDevice->DrawAuto();
	//}
	//else {

	//	CD3D10::g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ);
	//	/*
	//	Assume no geometry shader or no multipass geometry emmsion, use regular draw methods
	//	*/
	//	if(pInstanceCount) {

	//		CD3D10::g_pd3dDevice->DrawIndexedInstanced(triangelCount * 2 * 3, *pInstanceCount, 0, 0, 0);
	//	}
	//	else {

	//		CD3D10::g_pd3dDevice->DrawIndexed(triangelCount * 3 * 2, 0, 0);
	//	}
	//}
	return true;
}

/**
	Renders a batch of lines that have been bound to the device via a vertex Buffer.

	@author Dacre Denny
	@param elementCount the number of line segments to be drawn
	@return true if successful otherwise false
*/
bool CD3D10::DrawLineList(UINT elementCount) {

	if(elementCount == 0)
		return false;

	CD3D10::g_pd3dDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_LINELIST);
	CD3D10::g_pd3dDevice->Draw(elementCount * 2, 0);
	return true;
}
	
bool CD3D10::BindIndexBuffer(tResource* pIndexBuffer, UINT elementSize) {

	if(!pIndexBuffer || elementSize == 0)
		return false;

	if(pIndexBuffer->type != Render::INDEX_BUFFER)
		return false;

	ID3D10Buffer* pBuffer = (ID3D10Buffer*)(AS_D3D10_RESOURCE(pIndexBuffer->pResource));
	if(!pBuffer)
		return false;
	D3D10_BUFFER_DESC d;
	pBuffer->GetDesc(&d);
	switch(elementSize * 8) {
		
		case 16: 
			CD3D10::g_pd3dDevice->IASetIndexBuffer(pBuffer, DXGI_FORMAT_R16_UINT, 0);
			return true;

		case 32:
			CD3D10::g_pd3dDevice->IASetIndexBuffer(pBuffer, DXGI_FORMAT_R32_UINT, 0);
			return true;
	}
	return false;
}

bool CD3D10::BindStreamOutBuffer(tResource* pStreamOutBuffer, UINT elementSize) {

	if(elementSize == 0 || !pStreamOutBuffer)
		return false;

	if(GetD3D10Type(pStreamOutBuffer) != D3D10_RESOURCE_DIMENSION_BUFFER)
		return false;
		
	ID3D10Buffer* pBuffer = (ID3D10Buffer*)pStreamOutBuffer->pResource;
	D3D10_BUFFER_DESC desc;
	pBuffer->GetDesc(&desc);

	if(!(desc.BindFlags & D3D10_BIND_STREAM_OUTPUT))
		return false;

	UINT offset[1] = {0};
	ID3D10Buffer* Buffer[1] = { (ID3D10Buffer*)pStreamOutBuffer->pResource };

	if(Buffer[0]) {

		ID3D10Buffer* pCurrentSOBuffer = NULL;
		UINT currentOffset[1] = {0};
		UINT currentStrides[1] = {0};
		ID3D10Buffer* currentBuffer[1] = { NULL };
		CD3D10::g_pd3dDevice->SOGetTargets(1, currentBuffer, currentOffset);

		if(currentBuffer[0] == pBuffer) {
		
			currentBuffer[0] = NULL;
			currentOffset[0] = 0;
			CD3D10::g_pd3dDevice->SOSetTargets(1, currentBuffer, currentOffset);
		}

		CD3D10::g_pd3dDevice->IAGetVertexBuffers(0, 1, currentBuffer, currentStrides, currentOffset);
		if(currentBuffer[0] == pBuffer) {
		
			currentBuffer[0] = NULL;
			currentOffset[0] = 0;
			CD3D10::g_pd3dDevice->IASetVertexBuffers(0, 1, currentBuffer, currentStrides, currentOffset);
		}
	}

	CD3D10::g_pd3dDevice->SOSetTargets(1, &Buffer[0], &offset[0]);

	return true;
}

bool CD3D10::BindVertexBuffer(tResource** pVertexBuffers, UINT* elementSizes, UINT BufferCount) {

	if(BufferCount == 0 || !pVertexBuffers || !elementSizes)
		return false;

	std::vector<UINT> offsets;
	std::vector<ID3D10Buffer*> Buffers;

	for(UINT i = 0; i < BufferCount; i++) {
	
		tResource* pResource = pVertexBuffers[i];
		if(!pResource)
			continue;

		if(GetD3D10Type(pResource) != D3D10_RESOURCE_DIMENSION_BUFFER)
			continue;

		offsets.push_back(0);
		Buffers.push_back((ID3D10Buffer*)pResource->pResource);
	}

	if(offsets.size() == 0)
		return false;

	CD3D10::g_pd3dDevice->IASetVertexBuffers( 0, Buffers.size(), &Buffers[0], elementSizes, &offsets[0]);
	return true;
}

/**
	Allows the client to fill the specified vertex Buffer resource with data. This function takes care
	of blocking the resource so that it can be safely modified in accordance with the device implementations
	requirements

	@author Dacre Denny
	@param pVertexBuffer the vertex Buffer to be modified
	@param sizeInBytes the size of the data being inserted into the specified Buffer
	@param pData pointer to the data being copied into the specified Buffer
	@return true if successful otherwise false
*/
bool CD3D10::FillVertexBuffer(Render::tResource* pVertexBuffer, UINT sizeInBytes, LPVOID pData) {

	if(!pVertexBuffer || !pData || sizeInBytes == 0)
		return false;

	if(!(pVertexBuffer->type == Render::VERTEX_BUFFER || pVertexBuffer->type == Render::INDEX_BUFFER) || 
		CD3D10::GetD3D10Type(pVertexBuffer) != D3D10_RESOURCE_DIMENSION_BUFFER)
		return false;

	UINT resourceSizeInBytes = 0;
	if(!CD3D10::GetBufferInfo(pVertexBuffer, &resourceSizeInBytes))
		return false;

	LPVOID pVertices		= NULL;
	ID3D10Buffer* pBuffer	= (ID3D10Buffer*)pVertexBuffer->pResource;
	if(FAILED(pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVertices)))
		return false;
	
	memcpy_s(pVertices, resourceSizeInBytes, pData,  min(resourceSizeInBytes, sizeInBytes));
	pBuffer->Unmap();

	return true;
}

struct tMap{
	uint i;
	int iOther;
};

bool CD3D10::CreateVertexIndicieBuffer(UINT sizeBytes,LPVOID pData,  uint vertexFormat, tResource** pVBOut, tResource** pIBOut) {

	if(!pData || !pVBOut || !pIBOut || sizeBytes == 0 || (vertexFormat & VERTEX_POSITION) == 0)
		return false;
	
	float epsilion = 0.1f;

	UINT resourceSizeInBytes = sizeBytes;
	uint vertexSize = GetVertexFormatSize(vertexFormat);
	
	uint vertexCount = resourceSizeInBytes / vertexSize;
	char* pVertices = NULL;
	HRESULT hr = S_OK;
	
	char* pBufferData = (char*)pData;
	

	std::vector<tMap> mapping; 

	for(uint i = 0; i < vertexCount; i++) {

		tMap m = {i, 0};
		mapping.push_back(m);
	}

	for(uint a = 0; a < vertexCount; a++) {

		tMap* pVtxA = &mapping[a];
		float a_x = *((float*)&pBufferData[(vertexSize * a) + (sizeof(float) * 0)]);
		float a_y = *((float*)&pBufferData[(vertexSize * a) + (sizeof(float) * 1)]);
		float a_z = *((float*)&pBufferData[(vertexSize * a) + (sizeof(float) * 2)]);

		for(uint b = 0; b < vertexCount; b++) {

			if(a == b) {
				mapping[b].iOther = mapping[b].i;
				continue;
			}

			float b_x = *((float*)&pBufferData[(vertexSize * b) + (sizeof(float) * 0)]);
			float b_y = *((float*)&pBufferData[(vertexSize * b) + (sizeof(float) * 1)]);
			float b_z = *((float*)&pBufferData[(vertexSize * b) + (sizeof(float) * 2)]);
	
			float d_x = b_x - a_x;
			float d_y = b_y - a_y;
			float d_z = b_z - a_z;

			if(d_x * d_x + d_y * d_y + d_z * d_z < epsilion * epsilion) {
 
				if(mapping[b].iOther != -1 || mapping[b].iOther != mapping[b].i)
					mapping[b].iOther = pVtxA->i;
			}
		}
	}
	
	uint adjCounter = 0;
	std::vector<uint> indicies;
	std::vector<uint> indiciesAdj;

	//uint* pIndiciesAjd = new uint[vertexCount];
	char* pBufferAdj = new char[resourceSizeInBytes];
	ZeroMemory(pBufferAdj, resourceSizeInBytes);
	//ZeroMemory(pIndiciesAjd, vertexCount * sizeof(uint));
	
	std::vector<uint> map_i = std::vector<uint>::vector(vertexCount);
	
	for(uint i = 0; i < vertexCount; i++) {

		tMap* pVert = &mapping[i];

		if(pVert->iOther != -1 && pVert->i != pVert->iOther) {

			while(pVert->iOther != -1 && pVert->i != pVert->iOther)			
				pVert = &mapping[pVert->iOther];
		}
		else {

			map_i[i] = adjCounter;
			memcpy(&pBufferAdj[adjCounter * vertexSize],  &pBufferData[pVert->i * vertexSize], vertexSize);
			adjCounter++;
		}

		indicies.push_back(pVert->i);
		/*pIndiciesAjd[indCounter] = pVert->i;
		indCounter++;*/
	}

	for(uint i = 0; i < indicies.size(); i++)
		indicies[i] = map_i[ indicies[i] ];
	/*for(uint i = 0; i < indCounter; i++)
		pIndiciesAjd[i] = map_i[ pIndiciesAjd[i] ];*/

	for(uint tri_a = 0; tri_a < indicies.size(); tri_a += 3) {

		uint ind_a[3] = {indicies[tri_a + 0], indicies[tri_a + 1], indicies[tri_a + 2]};
		uint adj_indicies[3] = {0,0,0};

		for(uint tri_b = 0; tri_b < indicies.size(); tri_b += 3) {

			if(tri_a == tri_b)
				continue;

			uint ind_b[3] = {indicies[tri_b + 0], indicies[tri_b + 1], indicies[tri_b + 2]};

			for(uint side = 0; side < 3; side++) {

				uint side_idx_0 = ind_a[(side + 0) % 3];
				uint side_idx_1 = ind_a[(side + 1) % 3];
				if(side_idx_0 == ind_b[0]) {

					if(side_idx_1 == ind_b[1])
						adj_indicies[side] = ind_b[2];
					else if(side_idx_1 == ind_b[2])
						adj_indicies[side] = ind_b[1];
				}
				else if(side_idx_0 == ind_b[1]) {

					if(side_idx_1 == ind_b[0])
						adj_indicies[side] = ind_b[2];
					else if(side_idx_1 == ind_b[2])
						adj_indicies[side] = ind_b[1];
				}
				else if(side_idx_0 == ind_b[2]) {

					if(side_idx_1 == ind_b[0])
						adj_indicies[side] = ind_b[1];
					else if(side_idx_1 == ind_b[1])
						adj_indicies[side] = ind_b[0];
				}
			}
		}

		indiciesAdj.push_back(ind_a[0]);
		indiciesAdj.push_back(adj_indicies[0]);
		indiciesAdj.push_back(ind_a[1]);
		indiciesAdj.push_back(adj_indicies[1]);
		indiciesAdj.push_back(ind_a[2]);
		indiciesAdj.push_back(adj_indicies[2]);

	}

	Render::tResource* pAdjVB = NULL;
	CreateVertexBuffer(adjCounter * vertexSize, false, &pAdjVB);
	FillVertexBuffer(pAdjVB, adjCounter * vertexSize, pBufferAdj);

	Render::tResource* pAdjIB = NULL;
	CreateIndexBuffer(indiciesAdj.size() * sizeof(uint), &pAdjIB);
	FillVertexBuffer(pAdjIB, indiciesAdj.size() * sizeof(uint), &indiciesAdj[0]);
	

	*pVBOut = pAdjVB;
	*pIBOut = pAdjIB;
	return true;
}

bool CD3D10::CreateBuffer(D3D10_BUFFER_DESC desc,tResource** pInOut) {

	ID3D10Buffer* pNewBuffer = NULL;

	VTRY
	{
		if(!pInOut)
			VTHROW_INTERNALERROR("Precondition failed");

		D3D10_VERIFY(CD3D10::g_pd3dDevice->CreateBuffer( &desc, NULL, &pNewBuffer))
		
		if(*pInOut) {
			
			if((*pInOut)->type != Render::VERTEX_BUFFER)
				VTHROW("Invalid resource type encountered")

			ID3D10Buffer* pInBuffer = (ID3D10Buffer*)(*pInOut)->pResource;
			if(!pInBuffer) {

				(*pInOut)->pResource = pNewBuffer;
			}
			else {

				FOREACH(Render::tResource*, i, Render::g_Resources) {

					Render::tResource* pIt = *i;
					if(!pIt)
						VTHROW("Invalid resource encountered")

					if(pInBuffer == pIt->pResource) {

						RELEASE_D3D10_RESOURCE(pIt->pResource);
						pIt->pResource = pNewBuffer;
						break;
					}
				}
			}
		} 
		else {
			
			Render::tResource* newResource = new Render::tResource();
			newResource->pResource	= pNewBuffer;
			newResource->type		= ((desc.BindFlags & D3D10_BIND_VERTEX_BUFFER) == 0) ? Render::INDEX_BUFFER : Render::VERTEX_BUFFER;
			Render::g_Resources.push_back(newResource);
		
			if(pInOut)
				*pInOut = newResource;
		}

		return true;
	}
	VCATCHONLY;

	RELEASE_D3D10_RESOURCE(pNewBuffer);
	return false;
}

/**
	Creates an index Buffer resource under this device. If the resource that is specified already 
	exists as a Buffer resource then it is assumed to have been created from an instance of a device 
	of this type. It will be recreated to satisfy the input parameters.

	@author Dacre Denny
	@param sizeBytes size of the resulting Buffer
	@param isStreamOut indicates if this Buffer will be used to store streamed shader data
	@param pInOut pointer to address of desitnation resource
	@return true if successful otherwise false
*/
bool CD3D10::CreateIndexBuffer(UINT sizeBytes, tResource** pInOut) {

	ID3D10Buffer* pNewBuffer = NULL;
	D3D10_BUFFER_DESC BufferDesc;

	VTRY
	{
		if(!pInOut || sizeBytes == 0)
			VTHROW_INTERNALERROR("Precondition failed");

		BufferDesc.Usage			= D3D10_USAGE_DYNAMIC;
		BufferDesc.ByteWidth		= sizeBytes;
		BufferDesc.BindFlags		= D3D10_BIND_INDEX_BUFFER;
		BufferDesc.CPUAccessFlags	= D3D10_CPU_ACCESS_WRITE;
		BufferDesc.MiscFlags		= 0;

		if(!CD3D10::CreateBuffer(BufferDesc, pInOut))
			VTHROW("Failed to create Buffer")

		return true;
	}
	VCATCHONLY;

	RELEASE_D3D10_RESOURCE(pNewBuffer);
	return false;
}

/**
	Creates a vertex Buffer resource under this device. If the resource that is specified already 
	exists as a Buffer resource then it is assumed to have been created from an instance of a device 
	of this type. It will be recreated to satisfy the input parameters.

	@author Dacre Denny
	@param sizeBytes size of the resulting Buffer
	@param isStreamOut indicates if this Buffer will be used to store streamed shader data
	@param pInOut pointer to address of desitnation resource
	@return true if successful otherwise false
*/
bool CD3D10::CreateVertexBuffer(UINT sizeBytes, bool isStreamOut, Render::tResource** pInOut) {

	ID3D10Buffer* pNewBuffer = NULL;
	D3D10_BUFFER_DESC BufferDesc;

	VTRY
	{
		if(!pInOut || (!isStreamOut && sizeBytes == 0))
			VTHROW_INTERNALERROR("Precondition failed");

		BufferDesc.Usage			= isStreamOut ? D3D10_USAGE_DEFAULT : D3D10_USAGE_DYNAMIC;
		BufferDesc.ByteWidth		= isStreamOut ? CD3D10::STREAMOUT_MAX * sizeof(float) : sizeBytes;
		BufferDesc.BindFlags		= isStreamOut ? D3D10_BIND_STREAM_OUTPUT | D3D10_BIND_VERTEX_BUFFER : D3D10_BIND_VERTEX_BUFFER;
		BufferDesc.CPUAccessFlags	= isStreamOut ? 0 : D3D10_CPU_ACCESS_WRITE;
		BufferDesc.MiscFlags		= 0;

		if(!CD3D10::CreateBuffer(BufferDesc, pInOut))
			VTHROW("Failed to create Buffer")

		return true;
	}
	VCATCHONLY;

	RELEASE_D3D10_RESOURCE(pNewBuffer);
	return false;
}

/**
	Aquires a resource view from the specified resource if it is valid and of the correct type.
	The function assumes the resource was created under a render instance of this implementation.
	If the resource is not of the correct type, the function will return false.

	@author Dacre Denny
	@param pTexture the resource to be analysed
	@param pOut pointer to address of desitnation texture resource view
	@return true if successful otherwise false
*/
bool CD3D10::GetTextureView(Render::tResource* pTexture, ID3D10ShaderResourceView** pOut) {

	if(!pOut || !pTexture)
		return false;
	
	if(!pTexture->pResource)
		return false;
	
	LPVOID pInterface = NULL;
	if(S_OK != AS_D3D10_COM(pTexture->pResource)->QueryInterface(IID_ID3D10ShaderResourceView, &pInterface))
		return false;

	*pOut = (ID3D10ShaderResourceView*)pTexture->pResource;
	return true;
}

/**
	Aquires a device texture from the specified resource if it is valid and of the correct type.
	The function assumes the resource was created under a render instance of this implementation.
	If the resource is not of the correct type, the function will return false.

	@author Dacre Denny
	@param pTexture the resource to be analysed
	@param pOut pointer to address of desitnation device texture resource
	@param pDimensions optional pointer to variable storing the texture resources dimensions
	@return true if successful otherwise false
*/
bool CD3D10::GetTextureResource(Render::tResource* pTexture, ID3D10Resource** pOut, UINT *pDimensions) {

	if(!pTexture || !pOut)
		return false;
	
	if(pTexture->type != Render::TEXTURE)
		return false;

	ID3D10ShaderResourceView* pView = NULL;
	if(!GetTextureView(pTexture, &pView))
		return false;

	ID3D10Resource* pResource = NULL;
	D3D10_RESOURCE_DIMENSION type;
	pView->GetResource(&pResource);
	pResource->GetType(&type);
	UINT dimensions;

	switch(type) {
		case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
			dimensions = 1;
			break;
		case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
			dimensions = 2;
			break;
		case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
			dimensions = 3;
			break;
		default:
			return false;
		break;
	}

	*pOut = (ID3D10Resource*)pResource;
	if(pDimensions)
		*pDimensions = dimensions;
	return true;
}

/**
	Returns the size of the specified vertex Buffer resource. The function assumes 
	the resource was created under a render instance of this implementation. If the 
	resource is not of the correct type, the function will return false.

	@author Dacre Denny
	@param pBuffer the resource to be analysed
	@param pSizeInBytes pointer to variable storing the resources size in bytes
	@return true if successful otherwise false
*/
bool CD3D10::GetBufferInfo(Render::tResource* pBuffer, UINT* pSizeInBytes) {

	if(!pBuffer || !pSizeInBytes)
		return false;

	if(!(pBuffer->type == Render::VERTEX_BUFFER || pBuffer->type == Render::INDEX_BUFFER))
		return false;

	if(CD3D10::GetD3D10Type(pBuffer) != D3D10_RESOURCE_DIMENSION_BUFFER)
		return false;

	D3D10_BUFFER_DESC desc;
	((ID3D10Buffer*)pBuffer->pResource)->GetDesc(&desc);

	if(pSizeInBytes)
		*pSizeInBytes = desc.ByteWidth;

	return true;
}

/**
	Returns the dimensions of the specified texture resource. The function assumes 
	the resource was created under a render instance of this implementation. If the 
	resource is not of the correct type, the function will return false.

	@author Dacre Denny
	@param pBuffer the resource to be analysed
	@param pSizeInBytes pointer to variable storing the resources size in bytes
	@return true if successful otherwise false
*/
bool CD3D10::GetTextureInfo(Render::tResource* pTexture, UINT* pWidth, UINT* pHeight) {

	if(!pTexture || (!pWidth && !pHeight))
		return false;

	if(pTexture->type != Render::TEXTURE)
		return false;

	ID3D10Resource* pTextureResource = NULL;
	UINT dimensions;
	if(!GetTextureResource(pTexture, &pTextureResource, &dimensions))
		return false;

	UINT width, height;
	switch(dimensions) {
		case 1: {

			D3D10_TEXTURE1D_DESC desc;
			((ID3D10Texture1D*)pTextureResource)->GetDesc(&desc);
			width = desc.Width;
			height = 1;
												 } break;
		case 2: {

			D3D10_TEXTURE2D_DESC desc;
			((ID3D10Texture2D*)pTextureResource)->GetDesc(&desc);
			width = desc.Width;
			height = desc.Height;
												 } break;
		case 3: {

			D3D10_TEXTURE3D_DESC desc;
			((ID3D10Texture3D*)pTextureResource)->GetDesc(&desc);
			width = desc.Width;
			height = desc.Height;
												 } break;
		default: {
			if(pWidth)
				*pWidth = 0;
			if(pHeight)
				*pHeight = 0;
			return false;
				 } break;
	}

	if(pWidth)
		*pWidth = width;
	if(pHeight)
		*pHeight = height;

	return true;
}

/**
	Binds a texture resource to a texture unit on the device. The function assumes 
	the resource was created under a render instance of this implementation. If the 
	resource is not of the correct type, the function will will be unsuccesful. The
	valid range of stages is [0 - 15]. The function requires that a shader currently
	be bound to the device.

	@author Dacre Denny
	@param Stage stage or 0 based unit index to bind the associated texture resource
	@param pTexture pointer to the texture resource being bound
*/
void CD3D10::SetShaderTexture(DWORD Stage, Render::tResource* pTexture) {
	
	if(!pTexture)
		return;

	if(pTexture->type != Render::TEXTURE)		
		return;

	if(Stage < 0 || Stage > (16 - 1) || !CD3D10::g_pCurrentShader.IsValid())
		return;

	char varName[8] = {0};
	sprintf_s(varName, 8, "g_tex%i", (int)Stage);

	ID3D10EffectVariable* pSamplerVariable = CD3D10::g_pCurrentShader.m_pEffect->GetVariableByName(varName);
	if(!pSamplerVariable)
		return;
	if(!pSamplerVariable->IsValid())
		return;

	ID3D10EffectShaderResourceVariable* pShaderResourceVariable = pSamplerVariable->AsShaderResource();
	if(!pShaderResourceVariable)
		return;
	if(!pShaderResourceVariable->IsValid())
		return;

	pShaderResourceVariable->SetResource(pTexture ? (ID3D10ShaderResourceView*)pTexture->pResource : NULL);
}
		
/**
	Sets the device to a state ready for immediate rendering. This state change is reversed by
	calling EndRendering()

	@author Dacre Denny
*/
void CD3D10::BeginRendering() {

#define GREY_AMOUNT 0.075f
	if(CD3D10::g_pd3dDevice) {

		/*CD3D10::g_pd3dDevice->RSSetState(CD3D10::g_pBlendState);*/

		CD3D10::g_pd3dDevice->ClearRenderTargetView(CD3D10::g_pRenderTargetView, 
		D3DXCOLOR(GREY_AMOUNT,GREY_AMOUNT,GREY_AMOUNT,1.0f));
		
		CD3D10::g_pd3dDevice->ClearDepthStencilView(CD3D10::g_pRenderDepthStencilView, 
		D3D10_CLEAR_DEPTH, 1.0f, 0);

		
		CD3D10::DrawGrid();
	}
}

/**
	Concludes the device's rendering. This state change is reversed by calling BeginRendering()

	@author Dacre Denny
*/
void CD3D10::EndRendering() {

	if(CD3D10::g_pSwapChain) {

		CD3D10::g_pSwapChain->Present(0,0);
	}
}

/**
Retrieves a D3D10 shader varaible handle, respective of the specified parameter name. If the desired parameter
is a member of a data strucutre, the member can be accessed from an instance of the data structure by inserting
an '@' character between the two tokens

@param pShader the shader to retrieve the parameter from
@param pName the string representing the parameter in the shader to access
@param pOut pointer to address where the found parameter handle is stored
@return true if successful otherwise false
*/
bool CD3D10::GetShaderVariable(ID3D10Effect* pShader, LPCSTR pName, ID3D10EffectVariable** pOut) {

	try {

		if(!pName || !pShader || !pOut)
			throw tException();

		std::string name = std::string(pName);
		
		const int lb_idx = name.find_first_of('[');
		const int rb_idx = name.find_first_of(']');
		int index = -1;

		if(lb_idx >= 0 && rb_idx >= 0 && rb_idx > lb_idx) {

			std::string str_idx = name.substr(lb_idx + 1, (rb_idx - lb_idx) - 1);
			index = atoi(str_idx.c_str());
			name.erase(lb_idx, (rb_idx - lb_idx) + 1);
		}

		const int idx = name.find_first_of('@');
		/*
		If the name string is actually refering to a member of a data structure we need to do some extra things
		*/
		ID3D10EffectVariable* pVariable = NULL;
		if(idx != -1) {

			std::string structName = name.substr(0, idx);
			std::string memberName = name.substr(idx + 1, name.length() - idx);
			
			pVariable = CD3D10::g_pCurrentShader.m_pEffect->GetVariableByName(structName.c_str());
			if(!pVariable)
				throw tException();

			if(!pVariable->IsValid())
				throw tException();

			if(index >= 0) {
				
				pVariable = pVariable->GetElement(index);
			}
			pVariable = pVariable->GetMemberByName(memberName.c_str());
		}
		else {
		
			if(index >= 0) {
				
				pVariable = pVariable->GetElement(index);
			}
			pVariable = CD3D10::g_pCurrentShader.m_pEffect->GetVariableByName(pName);
		}

		if(!pVariable)
			throw tException();
		if(!pVariable->IsValid())
			throw tException();

		*pOut = pVariable;
		return true;
	}
	catch(tException exception) {

		if(pOut)
			*pOut = NULL;

		return false;
	}
}

/**
	Sets a varaible on the currently bound shader. The varaible is targeted by name
	and the function will attempt to assign the specified value to the target varaible
	if it exists

	@author Dacre Denny
	@param pName name of the target varaible
	@param value value to assign to the target variable if it exists
	@return true if successful otherwise false
*/
bool CD3D10::SetShaderFloat(LPCSTR pName, float value) {

	if(!CD3D10::g_pCurrentShader.IsValid())
		return false;

	ID3D10EffectVariable* pVariable = NULL;
	if(!GetShaderVariable(CD3D10::g_pCurrentShader.m_pEffect, pName, &pVariable))
		return false;

	ID3D10EffectScalarVariable* pScalarVariable = pVariable->AsScalar();
	
	if(!pScalarVariable)
		return false;
	if(!pScalarVariable->IsValid())
		return false;
	
	pScalarVariable->SetFloat(value);
	return true;
}

/**
	Sets a varaible on the currently bound shader. The varaible is targeted by name
	and the function will attempt to assign the specified value to the target varaible
	if it exists

	@author Dacre Denny
	@param pName name of the target varaible
	@param value value to assign to the target variable if it exists
	@return true if successful otherwise false
*/
bool CD3D10::SetShaderInt(LPCSTR pName, int value) {

	if(!CD3D10::g_pCurrentShader.IsValid())
		return false;

	ID3D10EffectVariable* pVariable = NULL;
	if(!GetShaderVariable(CD3D10::g_pCurrentShader.m_pEffect, pName, &pVariable))
		return false;

	ID3D10EffectScalarVariable* pScalarVariable = pVariable->AsScalar();
	if(!pScalarVariable)
		return false;

	pScalarVariable->SetInt(value);
	return true;
}

/**
	Sets a matrix on the currently bound shader. The matrix is targeted by name
	and the function will attempt to assign the dereference matrix value to the 
	target matrix if it exists

	@author Dacre Denny
	@param pName name of the target matrix
	@param value value to assign to the target variable if it exists
	@return true if successful otherwise false
*/
bool CD3D10::SetShaderMatrix(LPCSTR pName, D3DXMATRIX* pValue) {

	if(!pValue || !CD3D10::g_pCurrentShader.IsValid())
		return false;

	ID3D10EffectVariable* pVariable = NULL;
	if(!GetShaderVariable(CD3D10::g_pCurrentShader.m_pEffect, pName, &pVariable))
		return false;

	ID3D10EffectMatrixVariable* pMatrixdVariable = pVariable->AsMatrix();
	if(!pMatrixdVariable)
		return false;

	pMatrixdVariable->SetMatrix((float*)pValue);
	return true;
}

/**
	Sets a vector on the currently bound shader. The vector is targeted by name
	and the function will attempt to assign the dereference vector value to the 
	target vector if it exists

	@author Dacre Denny
	@param pName name of the target vector
	@param value value to assign to the target variable if it exists
	@return true if successful otherwise false
*/
bool CD3D10::SetShaderVector(LPCSTR pName, D3DXVECTOR4* pValue) {

	if(!pValue || !CD3D10::g_pCurrentShader.IsValid())
		return false;

	ID3D10EffectVariable* pVariable = NULL;
	if(!GetShaderVariable(CD3D10::g_pCurrentShader.m_pEffect, pName, &pVariable))
		return false;

	ID3D10EffectVectorVariable* pVectordVariable = pVariable->AsVector();
	if(!pVectordVariable)
		return false;

	pVectordVariable->SetFloatVector((float*)pValue);
	return true;
}

/**
	Binds the specified shader to the device, thus making it the devices current
	shader. This side effect can be reversed by calling EndShader(). This function 
	assumes that the resource being released were created with a device instance 
	that matched this device implementation.

	@author Dacre Denny
	@param pShader the shader resource to be bound to the device instance
	@param isInstanced indicates weather or not this shader should execute any instancing code if applicable
	@param pPasses optional pointer to varaible where the shaders number of passes can be stored
	@return true if successful otherwise false
*/
bool CD3D10::BeginShader(const Render::tShader* pShader, bool isInstanced, UINT* pPasses) {

	if(!pShader)
		return false;

	if(!pShader->pInputDeclaration || !pShader->pEffect)
		return false;

	ID3D10Effect* pShaderEffect = (ID3D10Effect*)pShader->pEffect;

	LPCSTR targetTechnqiue = isInstanced ? "Technique_Instanced" : "Technique_Standard";
	if(!HasTechnique(pShaderEffect, targetTechnqiue))
		return false;

	if(!GetTechniquePassCount(pShaderEffect, targetTechnqiue, pPasses))
		return false;
	
	CD3D10::g_pd3dDevice->IASetInputLayout(((ID3D10InputLayout**)pShader->pInputDeclaration)[isInstanced ? 1 : 0]);
	CD3D10::g_pCurrentShader.Set(pShaderEffect, pShaderEffect->GetTechniqueByName(targetTechnqiue));
	CD3D10::g_pCurrentShader.m_OnPass = 0;
	D3DXMATRIX matrixViewProjection;

	static float g_Time = 0.0f;

	Render::Singleton()->GetCameraViewProjection(&matrixViewProjection);
	Render::Singleton()->SetShaderMatrix( "ViewProj", &matrixViewProjection );
	Render::Singleton()->SetShaderVector( "ViewPosition", &D3DXVECTOR4(Render::g_Camera.m_Position, 0.0f));
	Render::Singleton()->SetShaderFloat("Time", g_Time += 0.1f);
	Render::Singleton()->SetShaderTexture(3, Render::g_pProceduralBaseData);

	if(!Scene::ApplyLights(pShader))
		return false;

	return true;
}

/**
	Unbinds the devices current shader from the device if it exists. This side effect can be reversed by 
	calling BeginShader().

	@author Dacre Denny
	@return true if successful otherwise false
*/
bool CD3D10::EndShader() {

	if(!CD3D10::g_pCurrentShader.IsValid())
		return false;

	CD3D10::g_pCurrentShader.Set(NULL, NULL);
	return true;
}

/**
	Activates a pass in the devices currently bound shader. Calling this function is 
	required in order to render geometry via the bound shader. Passes are of 0 based
	index.

	@author Dacre Denny
	@param pass the index of the pass to render by
	@return true if successful otherwise false
*/
bool CD3D10::BeginShaderPass(UINT pass) {

	if(!CD3D10::g_pCurrentShader.IsValid())
		return false;
	
	ID3D10EffectTechnique* pTechnique = CD3D10::g_pCurrentShader.m_pTechnique;
	if(!pTechnique)
		return false;

	ID3D10EffectPass* pPass = pTechnique->GetPassByIndex(pass);
	if(pPass) {
	
		if(SUCCEEDED(pPass->Apply(0))) {

			CD3D10::g_pCurrentShader.m_OnPass = pass;
			return true;
		}
	}

	return false;
}

/**
	Deactivates the current pass of the devices currently bound shader. This function
	has no effect for this renderer implementation.

	@author Dacre Denny
	@return true unconditionally
*/
bool CD3D10::EndShaderPass() {

	CD3D10::g_pCurrentShader.m_OnPass = 0;
	return true;
}

/**
	Activates the devices sprite batch to allow sprites to be rendered

	@author Dacre Denny
	@return true if successful otherwise false
*/
bool CD3D10::BeginSprites() {
	
	if(CD3D10::g_pSpriteBatch) {
	
		CD3D10::g_pSpriteBatch->Begin(0);
		return true;
	}

	return false;
}

/**
	Deactivates the devices sprite batch. Attempting to draw sprites without reactiving 
	will cause unexpected results

	@author Dacre Denny
	@return true if successful otherwise false
*/
bool CD3D10::EndSprites() {

	if(CD3D10::g_pSpriteBatch) {

		CD3D10::g_pSpriteBatch->Flush();
		CD3D10::g_pSpriteBatch->End();

		return true;
	}

	return false;
}

/**
	Renders text to the screen Buffer. Currently, a maximum of 128 characters will be displayed.
	Other parameters allow control over positioning, color, etc

	@param text the text string to render
	@param type the font type to use (the device supports two text fonts)
	@param color the color to draw this text as
	@param position vector describing the pixel position for the text to occupy
	@author Dacre Denny
	@return true if successful otherwise false
*/
void CD3D10::DrawString(DWORD type, D3DCOLOR color, D3DXVECTOR2& position, char* format, ...) {

	if(format != NULL && CD3D10::g_pFontBatch) {

		RECT window;
		CWindow::GetClientRectangle(&window);

		float x = position.x * float(window.right - window.left);
		float y = position.y * float(window.bottom - window.top);

		char Buffer[256] = {0};
		va_list args;
		va_start (args, format);
		vsprintf (Buffer,format, args);
		perror (Buffer);
		va_end (args);

		Buffer[256 - 1] = '\n';
		RECT r;
		r.left = x;
		r.top = y;
		r.right = r.left + 10;
		r.bottom = r.top + 10;

		
		
		CD3D10::g_pFontBatch->Begin(D3DX10_SPRITE_SAVE_STATE);
		CD3D10::g_pd3dxFontTitle->DrawTextA(CD3D10::g_pFontBatch, Buffer, -1, &r, DT_NOCLIP, color);
		CD3D10::g_pFontBatch->Flush();
		CD3D10::g_pFontBatch->End();

		
		/*
		Discovering that this was nessisary inorder to draw fonts and sprites took forever...
		*/
		CD3D10::g_pd3dDevice->OMSetBlendState(NULL, NULL, 0xffffffff);
//		CD3D10::g_pd3dDevice->OMSetDepthStencilState(NULL, 0);
	}
}

/**
	Renders a passed sprite directly to the screen Buffer. Other parameters allow control over 
	positioning, scale, etc

	@param text the text string to render
	@param type the font type to use (the device supports two text fonts)
	@param color the color to draw this text as
	@param pSrc rectangle describing the space for the text to occupy
	@author Dacre Denny
	@return true if successful otherwise false
*/
void CD3D10::DrawSprite(tResource* pTexture, D3DXVECTOR2& position, D3DXVECTOR2& scale, RECT* pSrc) {

	UINT width, height;
	if(!CD3D10::GetTextureInfo(pTexture, &width, &height))
		return;

	D3DXVECTOR2 coordTL;
	D3DXVECTOR2 coordDim;
	if(pSrc) {

		coordTL.x = (float)pSrc->left / (float)width;
		coordTL.y = (float)pSrc->top / (float)height;

		coordDim.x = (float)(pSrc->right - pSrc->left - 1) / (float)width;
		coordDim.y = (float)(pSrc->bottom - pSrc->top - 1) / (float)height;
	}
	else {
		
		coordTL.x = 0.0f;
		coordTL.y = 0.0f;

		coordDim.x = 1.0f;
		coordDim.y = 1.0f;
	}

	RECT window;
	CWindow::GetClientRectangle(&window);

	//float ratio = float(window.bottom - window.top) / float(window.right - window.left);
	float x_scale = float(coordDim.x * width) / float(window.right - window.left);
	float y_scale = float(coordDim.y * height) / float(window.bottom - window.top);

	D3DX10_SPRITE inst;
	D3DXMATRIX tmp,ti, t, s;
	D3DXMatrixScaling(&s, 
		x_scale*2,
		y_scale*2,
		0); 
	D3DXMatrixTranslation(&ti, 
		 .5,
		 -.5, 0);

	D3DXVECTOR2 p = position; 
	D3DXMatrixTranslation(&t, (((p.x) - 0.5) * 2),
		(0.5 - p.y) * 2, 0);
 
	D3DXMatrixMultiply(&tmp, &ti, &s);
	D3DXMatrixMultiply(&inst.matWorld, &tmp, &t);
	inst.ColorModulate = D3DXCOLOR(1,1,1,0);
	inst.pTexture = (ID3D10ShaderResourceView*)(pTexture->pResource);
	inst.TexCoord = coordTL;
	inst.TexSize = coordDim;
	inst.TextureIndex = 0;
	CD3D10::g_pSpriteBatch->DrawSpritesImmediate(&inst, 1,0,0);
}